package net.minecraft.src;

import java.util.Random;

public class Inscription {
	public int size;
	public int pattern[][];
	public String name;
	public String command;
	
	public Inscription(int size) {
		this.size = size;
		pattern = new int[size][size];
	}
	
	public Inscription(String name) {
		this.name = name;
	}
	
	public Inscription(int size, String name) {
		this(size);
		this.name = name;
	}
	
	public Inscription(int... pattern) {
		if (pattern == null) {
			return;
		}
		for (int i=3;i<13;i+=2) {
			if (pattern.length/i == i) {
				this.size = i;
				this.pattern = new int[size][size];
				break;
			}
		}
		
		int px = 0;
		int pz = 0;
		for (int i=0; i<pattern.length;i++) {

			this.pattern[px][pz] = pattern[i];
			pz++;
			if (pz >= size) {
				px++;
				pz = 0;
			}
		}
	}
	
	public Inscription(int size, String name, String command, int... pattern) {
		this(pattern);
		this.size = size;
		this.name = name;
		this.command = command;
	}
	
	
	
	
	
	
	
	
	public static void doInscription(String command, EntityPlayer ep, World world) {
		System.out.println("Command is " + command);
		int posX = InscriptionManager.prevBlockX;
		int posY = InscriptionManager.prevBlockY;
		int posZ = InscriptionManager.prevBlockZ;
		
		//destruction
		if (command == "enchantFireball") {
			if(wieldingScepter(ep)){
				setEnchantment("fireball", ep);
				sendEnchantmentText("Fireball", ep);
				wipeChalk(world, InscriptionManager.fireball.size, posX, posY, posZ, Block.fire.blockID);
			}
		}
		else if (command == "enchantLightning") {
			if(wieldingScepter(ep)){
				setEnchantment("lightning", ep);
				sendEnchantmentText("Lightning", ep);
			}
		}
		else if (command.equalsIgnoreCase("bulkMiner")) {
			if (wieldingScepter(ep)) {
				setEnchantment("bulkMiner", ep);
				sendEnchantmentText("Bulk Miner", ep);
			}

		}
		//conjure
		if (command == "giveCake") {
			ep.inventory.addItemStackToInventory(new ItemStack(Item.cake));
			wipeChalk(world, InscriptionManager.cake.size, posX, posY, posZ, Block.cake.blockID);
		}
		else if (command == "giveRail") {
			ep.inventory.addItemStackToInventory(new ItemStack(Block.rail));
		}
		
		else if (command == "giveShears") {
			ep.inventory.addItemStackToInventory(new ItemStack(Item.shears));
		}
		else if (command == "giveDirection") {
			ep.addChatMessage("This is north.");
			world.setBlockWithNotify(posX - 1, posY, posZ, mod_Inscription.chalkDustRed.blockID);
		}
		//build
		if(command == "tunnelNorth" || command == "tunnelSouth" || command == "tunnelEast" || command == "tunnelWest"){
			int size = InscriptionManager.tunnelNorth.size;
			boolean[][] pattern = new boolean[size][size];
			
			readPatternAndMark(world, pattern, mod_Inscription.chalkDustBlue, size, posX, posY, posZ);
			if(command.startsWith("tunnel")){
					new InscriptionThread(command).setWorld(world).setPattern(pattern).setBlockID(0).setSize(size)
					.setPosX(posX).setPosY(posY).setPosZ(posZ).setCommand(command).setShouldExplode(true).setPlaySound(true);
			}

		}
		else if(command == "bridgeNorth" || command == "bridgeSouth" || command == "bridgeEast" || command == "bridgeWest"){
			ep.addChatMessage("Building bridge");
			buildBridge(world, posX, posY, posZ, command);
		}
		else if(command == "stairsDown"){
			buildStairs(world, posX, posY, posZ, command);
			wipeChalk(world, InscriptionManager.stairsDown.size, posX, posY, posZ, 0);
		}
		else if (command == "buildShack") {
			int size = InscriptionManager.shack.size;
			boolean[][] pattern = new boolean[size][size];
			
			readPatternAndMark(world, pattern, mod_Inscription.chalkDustBlue, size, posX, posY, posZ);
			buildFromPattern(world, pattern, Block.planks.blockID, size, posX, posY, posZ, command);
		}
		else if(command == "buildHut"){
			int size = InscriptionManager.hut.size;
			boolean[][] pattern = new boolean[size][size];
			
			readPatternAndMark(world, pattern, mod_Inscription.chalkDustBlue, size, posX, posY, posZ);
			buildFromPattern(world, pattern, Block.planks.blockID, size, posX, posY, posZ, command);
		}
		else if(command == "buildHouse"){
			int size = InscriptionManager.house.size;
			boolean[][] pattern = new boolean[size][size];
			
			readPatternAndMark(world, pattern, mod_Inscription.chalkDustBlue, size, posX, posY, posZ);
			buildFromPattern(world, pattern, Block.planks.blockID, size, posX, posY, posZ, command);
		}
		//growth
		if(command == "growTree"){
			Random rand = new Random();
			if (world.getBlockId(posX,posY-1,posZ) == Block.dirt.blockID || world.getBlockId(posX,posY-1,posZ) == Block.grass.blockID) {
				world.setBlockWithNotify(posX, posY, posZ, Block.sapling.blockID);
				((BlockSapling)Block.sapling).growTree(world, posX, posY, posZ, rand);
				wipeChalk(world, InscriptionManager.tree.size, posX, posY, posZ, 0);
			}
			else {
				ep.addChatMessage("Cannot grow tree here.");
			}
		}
		else if(command == "growFlower"){
			Random rand = new Random();
			int blockID = Block.plantRed.blockID;
			if(rand.nextInt(2) == 1) blockID = Block.plantYellow.blockID;
			world.setBlockWithNotify(posX, posY, posZ, blockID);
			wipeChalk(world, InscriptionManager.flower.size, posX, posY, posZ, 0);
		}
		//teleport
		if(command == "senderNode"){
			int[] pattern = readSignature(world, true, posX, posY, posZ);
			
			TeleportNode node = new TeleportNode(pattern, posX, posY, posZ, true);
			TeleportManager.doTeleport(ep, node);
		}
		else if(command == "receiverNode"){
			int[] pattern = readSignature(world, false, posX, posY, posZ);
			
			TeleportNode node = new TeleportNode(pattern, posX, posY, posZ, false);
			TeleportManager.registerNode(ep, node);
		}
		else if(command == "marker"){
			int[] pattern = new int[]{-1, -1, -1, -1};
			
			TeleportNode node = new TeleportNode(pattern, posX, posY, posZ, false);
			TeleportManager.registerMarker(ep, node);
			wipeChalk(world, InscriptionManager.mark.size, posX, posY, posZ, 0);
		}
		else if(command == "recall"){
			TeleportManager.useRecall(ep);
			wipeChalk(world, InscriptionManager.recall.size, posX, posY, posZ, 0);
		}
		else if(command == "home"){
			TeleportManager.doRespawn(ep);
			
//			ChunkCoordinates spawnCoord = ep.getPlayerSpawnCoordinate();
//			if(spawnCoord != null){
//				ep.addChatMessage("Teleporting to spawn...");
//				ep.setPositionAndRotation(spawnCoord.x + 0.5, spawnCoord.y, spawnCoord.z + 0.5, ep.rotationYaw, ep.rotationPitch);
//			}
//			else ep.addChatMessage("Spawn point not found.");
		}
	}
	
	//WIP
	public static void buildStairs(World world, int x, int y, int z, String command){
		if(command.equalsIgnoreCase("stairsDown")){
			int stairID = Block.stairCompactCobblestone.blockID;
			int cobbleID = Block.cobblestone.blockID;
			int stairY = y - 1;
			int[] stairPattern = new int[]{cobbleID, stairID, stairID, stairID, stairID, stairID};
			for(int count = 0; count < 2; count++){
				for(int goNorth = 0; stairY > 0 && goNorth < stairPattern.length; goNorth++){
					world.setBlock(x - goNorth, stairY, z, stairPattern[goNorth]);
					stairY--;
				}
				for(int goWest = 0; stairY > 0 && goWest < stairPattern.length; goWest++){
					world.setBlock(x, stairY, z + goWest, stairPattern[goWest]);
					stairY--;
				}
				for(int goSouth = 0; stairY > 0 && goSouth < stairPattern.length; goSouth++){
					world.setBlock(x + goSouth, stairY, z, stairPattern[goSouth]);
					stairY--;
				}
				for(int goEast = 0; stairY > 0 && goEast < stairPattern.length; goEast++){
					world.setBlock(x, stairY, z - goEast, stairPattern[goEast]);
					stairY--;
				}
			}
		}
	}
	
	public static void buildBridge(World world, int x, int y, int z, String command)
	{
		if(command.equalsIgnoreCase("bridgeNorth")){
			int bridgeX = x - 1;
			int bridgeY = y - 1;
			int bridgeZ = z;
			int torch = 0;
			int repeat = 0;
			while(blocksWithinRange(world, 1, bridgeX, bridgeY, bridgeZ, 0) && repeat <= 34){
				for(int posY = bridgeY; posY < bridgeY + 3; posY++){
					for(int posZ = bridgeZ - 2; posZ < bridgeZ + 3; posZ++){
						if((torch == 3 && posY == bridgeY + 2) && (posZ == bridgeZ - 2 || posZ == bridgeZ + 2))
							world.setBlockWithNotify(bridgeX, posY, posZ, Block.torchWood.blockID);
						else if((torch == 3 && posY == bridgeY + 1) && (posZ == bridgeZ - 2 || posZ == bridgeZ + 2))
							world.setBlockWithNotify(bridgeX, posY, posZ, Block.planks.blockID);
						else if(posY == bridgeY + 1 && (posZ == bridgeZ - 2 || posZ == bridgeZ + 2))
							world.setBlockWithNotify(bridgeX, posY, posZ, Block.fence.blockID);
						else if(posY == bridgeY)
							world.setBlockWithNotify(bridgeX, posY, posZ, Block.planks.blockID);
					}
				}
				if(torch == 3) torch = 0;
				else torch++;
				bridgeX--;
				repeat++;
			}
		}
		else if(command.equalsIgnoreCase("bridgeSouth")){
			int bridgeX = x + 1;
			int bridgeY = y - 1;
			int bridgeZ = z;
			int torch = 0;
			int repeat = 0;
			while(blocksWithinRange(world, 3, bridgeX, bridgeY, bridgeZ, 0) && repeat <= 34){
				for(int posY = bridgeY; posY < bridgeY + 3; posY++){
					for(int posZ = bridgeZ - 2; posZ < bridgeZ + 3; posZ++){
						if((torch == 3 && posY == bridgeY + 2) && (posZ == bridgeZ - 2 || posZ == bridgeZ + 2))
							world.setBlockWithNotify(bridgeX, posY, posZ, Block.torchWood.blockID);
						else if((torch == 3 && posY == bridgeY + 1) && (posZ == bridgeZ - 2 || posZ == bridgeZ + 2))
							world.setBlockWithNotify(bridgeX, posY, posZ, Block.planks.blockID);
						else if(posY == bridgeY + 1 && (posZ == bridgeZ - 2 || posZ == bridgeZ + 2))
							world.setBlockWithNotify(bridgeX, posY, posZ, Block.fence.blockID);
						else if(posY == bridgeY)
							world.setBlockWithNotify(bridgeX, posY, posZ, Block.planks.blockID);
					}
				}
				if(torch == 3) torch = 0;
				else torch++;
				bridgeX++;
				repeat++;
			}
		}
		else if(command.equalsIgnoreCase("bridgeEast")){
			int bridgeX = x;
			int bridgeY = y - 1;
			int bridgeZ = z - 1;
			int torch = 0;
			int repeat = 0;
			while(blocksWithinRange(world, 2, bridgeX, bridgeY, bridgeZ, 0) && repeat <= 34){
				for(int posY = bridgeY; posY < bridgeY + 3; posY++){
					for(int posX = bridgeX - 2; posX < bridgeX + 3; posX++){
						if((torch == 3 && posY == bridgeY + 2) && (posX == bridgeX - 2 || posX == bridgeX + 2))
							world.setBlockWithNotify(posX, posY, bridgeZ, Block.torchWood.blockID);
						else if((torch == 3 && posY == bridgeY + 1) && (posX == bridgeX - 2 || posX == bridgeX + 2))
							world.setBlockWithNotify(posX, posY, bridgeZ, Block.planks.blockID);
						else if(posY == bridgeY + 1 && (posX == bridgeX - 2 || posX == bridgeX + 2))
							world.setBlockWithNotify(posX, posY, bridgeZ, Block.fence.blockID);
						else if(posY == bridgeY)
							world.setBlockWithNotify(posX, posY, bridgeZ, Block.planks.blockID);
					}
				}
				if(torch == 3) torch = 0;
				else torch++;
				bridgeZ--;
				repeat++;
			}
		}
		else if(command.equalsIgnoreCase("bridgeWest")){
			int bridgeX = x;
			int bridgeY = y - 1;
			int bridgeZ = z + 1;
			int torch = 0;
			int repeat = 0;
			while(blocksWithinRange(world, 0, bridgeX, bridgeY, bridgeZ, 0) && repeat <= 34){
				for(int posY = bridgeY; posY < bridgeY + 3; posY++){
					for(int posX = bridgeX - 2; posX < bridgeX + 3; posX++){
						if((torch == 3 && posY == bridgeY + 2) && (posX == bridgeX - 2 || posX == bridgeX + 2))
							world.setBlockWithNotify(posX, posY, bridgeZ, Block.torchWood.blockID);
						else if((torch == 3 && posY == bridgeY + 1) && (posX == bridgeX - 2 || posX == bridgeX + 2))
							world.setBlockWithNotify(posX, posY, bridgeZ, Block.planks.blockID);
						else if(posY == bridgeY + 1 && (posX == bridgeX - 2 || posX == bridgeX + 2))
							world.setBlockWithNotify(posX, posY, bridgeZ, Block.fence.blockID);
						else if(posY == bridgeY)
							world.setBlockWithNotify(posX, posY, bridgeZ, Block.planks.blockID);
					}
				}
				if(torch == 3) torch = 0;
				else torch++;
				bridgeZ++;
				repeat++;
			}
		}
	}
	
	public static boolean blocksWithinRange(World world, int direction, int bridgeX, int bridgeY, int bridgeZ, int compareBlockID){
		switch(direction){
		case(0): //west
		{
			for(int posY = bridgeY; posY < bridgeY + 3; posY++){
				for(int posX = bridgeX - 2; posX < bridgeX + 3; posX++){
					if(world.getBlockId(posX, posY, bridgeZ) != 0) return false;
				}
			}
			break;
		}
		case(1): //north
		{
			for(int posY = bridgeY; posY < bridgeY + 3; posY++){
				for(int posZ = bridgeZ - 2; posZ < bridgeZ + 3; posZ++){
					if(world.getBlockId(bridgeX, posY, posZ) != 0) return false;
				}
			}
			break;
		}
		case(2): //east
		{
			for(int posY = bridgeY; posY < bridgeY + 3; posY++){
				for(int posX = bridgeX - 2; posX < bridgeX + 3; posX++){
					if(world.getBlockId(posX, posY, bridgeZ) != 0) return false;
				}
			}
			break;
		}
		case(3): //south
		{
			for(int posY = bridgeY; posY < bridgeY + 3; posY++){
				for(int posZ = bridgeZ - 2; posZ < bridgeZ + 3; posZ++){
					if(world.getBlockId(bridgeX, posY, posZ) != 0) return false;
				}
			}
			break;
		}
		}
		return true;
	}
	
	public static void buildFromPattern(World world, boolean[][] placeBlock, int blockIdToPlace, int size, int x, int y, int z, String command)
	{
		int stopX = size / 2;
		int stopZ = size / 2;
		int boolX = 0;
		for(int posX = stopX * -1; posX < stopX + 1; posX++){
			int boolZ = 0;
			for(int posZ = stopZ * -1; posZ < stopZ + 1; posZ++){
				for(int posY = 0; posY < size - 2; posY++){
					if(placeBlock[boolX][boolZ]) world.setBlockWithNotify(x + posX, y + posY, z + posZ, blockIdToPlace);
				}
				boolZ++;
			}
			boolX++;
		}
		
		if(command.equalsIgnoreCase("buildShack") || command.equalsIgnoreCase("buildHouse")){
			for(int posY = 2; posY < size - 2; posY++){
				world.setBlockWithNotify(x + stopX, y + posY, z, blockIdToPlace);
			}
			int innerSize = size - 2;
			int innerY = size - 2;
			while(innerSize > 1){
				int innerX = innerSize / 2;
				int innerZ = innerSize / 2;
				for(int posX = innerX * -1; posX < innerX + 1; posX++){
					for(int posZ = innerZ * -1; posZ < innerZ + 1; posZ++){
						world.setBlockWithNotify(x + posX, y + innerY, z + posZ, blockIdToPlace);
					}
				}
				innerSize -= 2;
				innerY++;
			}
		}
		else if(command.equalsIgnoreCase("buildHut")){
			for(int posY = 2; posY < size - 2; posY++){
				world.setBlockWithNotify(x + stopX, y + posY, z, blockIdToPlace);
			}
			int innerSize = size - 2;
			int innerY = size - 2;
			while(innerSize > 3){
				int innerX = innerSize / 2;
				int innerZ = innerSize / 2;
				for(int posX = innerX * -1; posX < innerX + 1; posX++){
					for(int posZ = innerZ * -1; posZ < innerZ + 1; posZ++){
						if(Math.abs(posX) + Math.abs(posZ) < innerSize - 2)
							world.setBlockWithNotify(x + posX, y + innerY, z + posZ, blockIdToPlace);
					}
				}
				innerSize -= 2;
				innerY++;
			}
		}
	}
	
	public static int[] readSignature(World world, boolean isSender, int x, int y, int z){
		int[] signature = new int[4];
		int offset = 2;
		if(isSender){
			signature[0] = world.getBlockId(x - offset, y - 1, z + offset); //NW
			signature[1] = world.getBlockId(x - offset, y - 1, z - offset); //NE
			signature[2] = world.getBlockId(x + offset, y - 1, z + offset); //SW
			signature[3] = world.getBlockId(x + offset, y - 1, z - offset); //SE
		}
		else{
			offset = 1;
			signature[0] = world.getBlockId(x - offset, y - 1, z); //N
			signature[1] = world.getBlockId(x, y - 1, z - offset); //E
			signature[2] = world.getBlockId(x, y - 1, z + offset); //W
			signature[3] = world.getBlockId(x + offset, y - 1, z); //S
		}
		return signature;
	}
	
	public static int[] readPattern(World world, int size, int x, int y, int z){
		int[] pattern = new int[size * size];
		int stopX = size / 2;
		int stopZ = size / 2;
		int i = 0;
		for(int posX = stopX * -1; posX < stopX + 1; posX++){
			for(int posZ = stopZ * -1; posZ < stopZ + 1; posZ++){
				pattern[i] = world.getBlockId(x + posX, y, z + posZ);
				i++;
			}
		}
		return pattern;
	}
	
	public static void readPatternAndMark(World world, boolean[][] placeBlock, Block readBlock, int size, int x, int y, int z)
	{
		int stopX = size / 2;
		int stopZ = size / 2;
		int boolX = 0;
		for(int posX = stopX * -1; posX < stopX + 1; posX++){
			int boolZ = 0;
			for(int posZ = stopZ * -1; posZ < stopZ + 1; posZ++){
				if(world.getBlockId(x + posX, y, z + posZ) == readBlock.blockID) placeBlock[boolX][boolZ] = true;
				boolZ++;
			}
			boolX++;
		}
	}
	
	public static void wipeInscription(World world, int size, int x, int y, int z, int replacementBlockIDblocks, int replacementBlockIDchalk)
	{
		wipeBlocks(world, size, x, y, z, replacementBlockIDblocks);
		wipeChalk(world, size, x, y, z, replacementBlockIDchalk);
	}
	
	public static void wipeBlocks(World world, int size, int x, int y, int z, int replacementBlockID)
	{
		int stopX = size / 2;
		int stopZ = size / 2;
		int beginDontRead = mod_Inscription.chalkDustRed.blockID;
		int endDontRead = mod_Inscription.chalkDustBlack.blockID;
		for(int posX = stopX * -1; posX < stopX + 1; posX++){
			for(int posZ = stopZ * -1; posZ < stopZ + 1; posZ++){
				int worldBlockId = world.getBlockId(x + posX, y, z + posZ);
				if(worldBlockId < beginDontRead || worldBlockId > endDontRead) world.setBlockWithNotify(x + posX, y, z + posZ, replacementBlockID);
			}
		}
	}
	
	public static void wipeChalk(World world, int size, int x, int y, int z, int replacementBlockID)
	{
		int stopX = size / 2;
		int stopZ = size / 2;
		int beginRead = mod_Inscription.chalkDustRed.blockID;
		int endRead = mod_Inscription.chalkDustBlack.blockID;
		for(int posX = stopX * -1; posX < stopX + 1; posX++){
			for(int posZ = stopZ * -1; posZ < stopZ + 1; posZ++){
				int worldBlockId = world.getBlockId(x + posX, y, z + posZ);
				if(worldBlockId >= beginRead && worldBlockId <= endRead) {
					world.setBlockWithNotify(x + posX, y, z + posZ, replacementBlockID);
					world.spawnParticle("smoke", x+posX, y, z+posZ, 0.0D, 0.0D, 0.0D);  
				}
			}
		}
	}
	
	public static boolean wieldingScepter(EntityPlayer ep) {
		if(ep.getCurrentEquippedItem().itemID >= mod_Inscription.scepterWood.shiftedIndex 
				&& ep.getCurrentEquippedItem().itemID <= mod_Inscription.scepterGold.shiftedIndex) {
			return true;
		}
		return false;
	}
	
	public static void setEnchantment(String enchantment, EntityPlayer ep) {
		if (wieldingScepter(ep)) {
			((ItemScepter)ep.inventory.getCurrentItem().getItem()).setEnchantment(enchantment);
		}
	}
	
	public static void sendEnchantmentText(String text, EntityPlayer ep) {

		mod_Inscription.sendChatMessage("Inscription for " + ((ItemScepter)ep.inventory.getCurrentItem().getItem()).toolMaterial.name() + " set to " + text, 'a');
	}
}
